package com.atguigu.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.OrderTo;
import com.atguigu.common.to.SeckillOrderTo;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResVo;
import com.atguigu.gulimall.order.constant.OrderConstant;
import com.atguigu.gulimall.order.dao.OrderDao;
import com.atguigu.gulimall.order.entity.OrderEntity;
import com.atguigu.gulimall.order.entity.OrderItemEntity;
import com.atguigu.gulimall.order.entity.PaymentInfoEntity;
import com.atguigu.gulimall.order.enume.OrderStatusEnum;
import com.atguigu.gulimall.order.feign.CarFeignService;
import com.atguigu.gulimall.order.feign.MemberFeignService;
import com.atguigu.gulimall.order.feign.ProductFeignService;
import com.atguigu.gulimall.order.feign.WmsFeignService;
import com.atguigu.gulimall.order.interceptor.LoginUserInterceptor;
import com.atguigu.gulimall.order.pay.PayVo;
import com.atguigu.gulimall.order.service.OrderItemService;
import com.atguigu.gulimall.order.service.OrderService;
import com.atguigu.gulimall.order.service.PaymentInfoService;
import com.atguigu.gulimall.order.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    private ThreadLocal<OrderSubmitVo> confirmVo = new ThreadLocal<> ();

    @Autowired
    private MemberFeignService memberFeignService;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private CarFeignService carFeignService;

    @Autowired
    private WmsFeignService wmsFeignService;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page (
                new Query<OrderEntity> ().getPage (params),
                new QueryWrapper<OrderEntity> ()
        );

        return new PageUtils (page);
    }


    /**
     * 展示订单页数据
     *
     * @return
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo ();
        MemberResVo memberResVo = LoginUserInterceptor.loinUser.get ();
        System.out.println ("主线程" + Thread.currentThread ().getId ());

        //在自己的线程共享requestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes ();

        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync (() -> {
            System.out.println ("mem" + Thread.currentThread ().getId ());
            //每一个线程都来共享之前的请求数据
            RequestContextHolder.setRequestAttributes (requestAttributes);
            //1、远程查询所有的收获列表地址
            List<MemberAddressVo> address = memberFeignService.getAddress (memberResVo.getId ());
            confirmVo.setAddress (address);
        }, executor);


        CompletableFuture<Void> carItemsFuture = CompletableFuture.runAsync (() -> {
            System.out.println ("item" + Thread.currentThread ().getId ());
            RequestContextHolder.setRequestAttributes (requestAttributes);
            //2、远程查询购物车所有选中购物项
            List<OrderItemVo> currentUserCarItems = carFeignService.getCurrentUserCarItems ();
            confirmVo.setItems (currentUserCarItems);
            //feign在远程调用之前要用构造请求，调用很多拦截器
            //RequestInterceptor  interceptor : requestInterceptors
        }, executor).thenRunAsync (() -> {
            //不需要登录状态-》所以要在拦截器判断
            //继续异步调用、查询库存
            List<OrderItemVo> items = confirmVo.getItems ();
            //获取购物项id
            List<Long> collect = items.stream ().map (item -> item.getSkuId ()).collect (Collectors.toList ());
            //远程调用查库存
            R skuHasStock = wmsFeignService.getSkuHasStock (collect);
            List<SkuStockVo> dta = skuHasStock.getDta (new TypeReference<List<SkuStockVo>> () {
            });

            if (dta != null && dta.size() > 0) {
                //想要获取那个东西有没有库存、就非常简单了、转换map
                Map<Long, Boolean> map = dta.stream ().collect (Collectors.toMap (SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                confirmVo.setStocks (map);
            }
        });


        //3、查询积分
        Integer integration = memberResVo.getIntegration ();
        confirmVo.setIntegration (integration);
        //4、其他数据自动计算

        //4、放重令牌
        String token = UUID.randomUUID ().toString ().replace ("_", "");
        //给服务器一个放重令牌
        redisTemplate.opsForValue ().set (OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResVo.getId (), token, 30, TimeUnit.MINUTES); //30分钟为例

        //给页面一个防重令牌
        confirmVo.setOrderToken (token);

        CompletableFuture.allOf (addressFuture, carItemsFuture).get ();
        return confirmVo;
    }

    //同一个对象事务方法互调默认失效，原因 绕过了代理对象
    //事务使用代理对象来控制
    //abc是同一个service
    //Springboot事务还有一个坑、abc是一个service、a掉的是bc 、bc这两个方法做的任何事务都是没用的、都是和a公用一个事务、但是如果bService.b()、cService.c()、这样的事务设置是有用的 事务使用代理来控制的、如果直接掉b、c的自个方法、相当于跳过拉代理、相当于直接把bc方法复制粘贴过来了、没有任何区别、都是跟a公用一个事务、所以这种情况下、还想要笨方法内、我们同一个对象内方法互调、事务还要生效
    @Transactional(timeout = 30) //a事务的所有设置就传播到了和他公用一个事务的方法
    public void a() {
        //bc做任何设置都没用。都是和a公用一个事务
//        b (); //a事务
//        c (); //新事务(不回应)

        //也不行没用经过代理类、this也是当前对象
        //        this.b (); //a事务
        //        this.c (); //新事务(不回应)

        //有本类方法互调的都这么来做
        OrderServiceImpl o = (OrderServiceImpl) AopContext.currentProxy ();
        o.b ();
        o.c ();
        int i = 10 / 0;
    }

    @Transactional(propagation = Propagation.REQUIRED, timeout = 2)
    public void b() {
        //7s
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 2)
    public void c() {

    }

    /**
     * 分布式事务：
     * 整个订单的事务他操作自己的数据库没问题、远程操作的是远程的数据库、跟自己没用一点关系、order也链接不了远程的数据库、它肯定不能回滚
     * 同一个事务在一个链接里
     * <p>
     * 本地事务，在分布式系统，只能控制自己的回滚，控制不了其他的回滚
     * 分布式事务；最大的原因，网络问题+分布式机器
     * (isolation = Isolation.REPEATABLE_READ)
     *
     * @param vo
     * @return
     */
//    @GlobalTransactional
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo) {
        confirmVo.set (vo); //存储到thread里面用来共享
        SubmitOrderResponseVo response = new SubmitOrderResponseVo ();
        //页面所有传递过来的数据都放到thread
        MemberResVo memberResVo = LoginUserInterceptor.loinUser.get ();
        response.setCode (0); //只要有异常、code都会变成其他的代码

        //第一步验证令牌[令牌的对比和删除必须保证原子性]
        //0令牌失败  - 1、删除成功
        String orderToken = vo.getOrderToken ();
        //使用脚本代替下面注释的、脚本=验证令牌令牌的对比和删除必须保证原子性
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        //原子验证令牌和删除令牌
        Long result = redisTemplate.execute (new DefaultRedisScript<Long> (script, Long.class), Arrays.asList (OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResVo.getId ()), orderToken);
        if (result == 0L) {
            //令牌验证失败
            response.setCode (1);
            return response;
        } else {
            //令牌验证成功
            //下单：去创建订单，验证令牌，验价格，锁库存
            //1、创建订单、订单项等信息
            OrderCreateTo order = orderCreateTo ();
            //2、验价
            BigDecimal payAmount = order.getOrder ().getPayAmount ();
            BigDecimal payPrice = vo.getPayPrice (); //页面传递来的

            //计算的金额的绝对值相差范围小于0.01、就算是对比成功
            if (Math.abs (payAmount.subtract (payPrice).doubleValue ()) < 0.01) {
                //金额对比

                //TODO 3、保存订单、不但有订单还有订单项、所以抽取一个方法
                //只要保存成功、就接着锁库存
                saveOrder (order);
                //4、库存锁定、只要有异常回滚订单数据
                //订单号、所有订单项（skuId、skuName,num）
                WareSkuLockVo lockVo = new WareSkuLockVo ();
                lockVo.setOrderSn (order.getOrder ().getOrderSn ());

                //要锁的订单项数据
                List<OrderItemVo> collect = order.getOrderItems ().stream ().map (item -> {
                    OrderItemVo itemVo = new OrderItemVo ();
                    itemVo.setSkuId (item.getSkuId ()); //商品
                    itemVo.setCount (item.getSkuQuantity ()); //要锁几件
                    itemVo.setTitle (item.getSkuName ()); //商品名字
                    return itemVo;
                }).collect (Collectors.toList ());
                lockVo.setLocks (collect); //锁定的数据

                //TODO  4、远程锁库存、重要的操作
                //库存成功了，但是网络原因超时了，订单回滚、库存不滚
                R r = wmsFeignService.orderLockStock (lockVo);//调用远程服务锁定
                if (r.getCode () == 0) {
                    //锁成功了
                    response.setOrder (order.getOrder ()); //保存后的完整信息order.getOrder(
                    /**
                     * TODO 订单回滚、远程调用库存不回滚
                     * TODO 或者远程调用由于出现假问题、各种网络原因、及锁成功了网络断了、
                     * TODO 5、远程扣减积分 出异常  int i= 10/0;
                     */
//                    int i= 10/0;

                    //TODO 订单创建成功就给MQ发消息
                    rabbitTemplate.convertAndSend ("order-event-exchange", "order.create.order", order.getOrder ());
                    return response;
                } else {
                    //锁定失败
                    String msg = (String) r.get ("msg");
                    throw new NoStockException (msg);
//                    response.setCode (3);
//                    return response;

                }

            } else {
                response.setCode (2); //2:金额对比失败
                return response;
            }
        }
        /**
         *比如两次提交的非常快、这个人带了123这个令牌、两次直接点进来、然后都进来这个方法、然后从页面拿过来的令牌都是123、
         *  去redis中查 、都是123、他们两个对比都通过了、通过以后都执行了、执行完以后再来删令牌、删掉的话、还会是重复提交的问题、只要没删都会出现这个问题
         *  所以令牌验证通过一定要删、优先执行
         *  1、验证令牌令牌的对比和删除必须保证原子性
         *
         */
//        String redisToken = redisTemplate.opsForValue().get(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResVo.getId());
//        if (orderToken != null && orderToken.equals(redisToken)) {
//            //令牌验证通过
//            redisTemplate.delete(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResVo.getId());
//        } else {
//            //不通过
//        }
    }

    @Override
    public OrderEntity getOrderStatus(String orderSn) {
        OrderEntity order_sn = this.getOne (new QueryWrapper<OrderEntity> ().eq ("order_sn", orderSn));
        return order_sn;
    }

    /**
     * 定时关单
     * 订单服务关单
     */
    @Override
    public void closeOrder(OrderEntity entity) {
        //查询当前这个订单的最新状态
        OrderEntity orderEntity = this.getById (entity.getId ());
        //只有待付款才可以关单

        if (orderEntity.getStatus () == OrderStatusEnum.CREATE_NEW.getCode ()) {
            //关单
            OrderEntity update = new OrderEntity ();
            update.setId (entity.getId ());
            update.setStatus (OrderStatusEnum.CANCLED.getCode ()); //修改状态
            this.updateById (update);

            //取消订单、发送消息
            OrderTo orderTo = new OrderTo ();
            BeanUtils.copyProperties (orderEntity, orderTo);

            //发消息、如果此时正在运行这个方法、结果MQ服务器跟我们的网络突然出现闪断、这个消息没用发出去、消息一定保证百分百发出去
            //怎么保证？

            try {

                //方式一：  网络链接不上可以这马做
                //TODO 保证消息一定发出去，每一个消息都可以做好日志记录 (给数据库保存每一个消息的详细信息)
                //TODO 定期扫描数据库将失败的消息在发送一遍
                rabbitTemplate.convertAndSend ("order-event-exchange", "order.release.other", orderTo);
            } catch (Exception e) {
                //TODO 将没法发送的成功的消息进行重试
//                    while（）循环
            }
        }

    }

    /**
     * 封装支付参数
     * 根据订单号查询到订单详情
     * 进行给支付参数封装
     * 再根据订单号查到订单项、获取到第0个信息、从第0个信息获取订单名称、商品描述、返回出去、调用支付
     *
     * @param orderSn
     * @return
     */
    @Override
    public PayVo getOrderPay(String orderSn) {
        PayVo payVo = new PayVo (); //封装支付参数

        OrderEntity order = this.getOrderStatus (orderSn);//获取订单号
        //setScale 进位处理
        BigDecimal bigDecimal = order.getPayAmount ().setScale (2, BigDecimal.ROUND_UP);
        payVo.setTotal_amount (bigDecimal.toString ());// 付款金额 必填
        payVo.setOut_trade_no (order.getOrderSn ());// 商户订单号 必填


        List<OrderItemEntity> order_sn = orderItemService.list (new QueryWrapper<OrderItemEntity> ().eq ("order_sn", orderSn));
        OrderItemEntity itemEntity = order_sn.get (0);
        payVo.setSubject (itemEntity.getSkuName ()); // 订单名称 必填
        payVo.setBody (itemEntity.getSkuAttrsVals ()); //商品描述 可空

        return payVo;
    }

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        MemberResVo memberResVo = LoginUserInterceptor.loinUser.get ();
        IPage<OrderEntity> page = this.page (
                new Query<OrderEntity> ().getPage (params),
                new QueryWrapper<OrderEntity> ().eq ("member_id", memberResVo.getId ()).orderByDesc ("id")
        );

        //每一个订单遍历、把每一个订单拿来、重新在查一下当前的订单的订单项
        List<OrderEntity> order_sn = page.getRecords ().stream ().map (order -> {
            List<OrderItemEntity> orderItems = orderItemService.list (new QueryWrapper<OrderItemEntity> ().eq ("order_sn", order.getOrderSn ()));
            order.setItemEntities (orderItems);
            return order;
        }).collect (Collectors.toList ());
        page.setRecords (order_sn);
        return new PageUtils (page);
    }

    /**
     * 异步通知
     *
     * @return
     */
    @Override
    public String handlePayResult(PayAsyncVo payAsyncVo) {
        //交易流水
        PaymentInfoEntity entity = new PaymentInfoEntity ();
        entity.setAlipayTradeNo (payAsyncVo.getTrade_no ()); //流水号
        entity.setOrderSn (payAsyncVo.getOut_trade_no ());//订单号
        entity.setPaymentStatus (payAsyncVo.getTrade_status ());//交易状态  TRADE_SUCCESS
        entity.setCallbackTime (payAsyncVo.getNotify_time ());
        paymentInfoService.save (entity);

        //修改订单状态信息
        if (payAsyncVo.getTrade_status ().equals ("TRADE_SUCCESS") || payAsyncVo.getTrade_status ().equals ("TRADE_FINISHED")) {
            //支付成功
            System.out.println ("异步回调修改订单状态");
            String outTradeNo = payAsyncVo.getOut_trade_no ();
            this.baseMapper.updateOrderStatus (outTradeNo, OrderStatusEnum.PAYED.getCode ());
        }
        return "success";
    }

    @Override
    public void createSeckillOrder(SeckillOrderTo orderTo) {
        //价格* 数量
        BigDecimal multiply = orderTo.getSeckillPrice ().multiply (new BigDecimal ("" + orderTo.getNum ()));
        //TODO 保存订单信息
        OrderEntity entity = new OrderEntity ()
                .setOrderSn (orderTo.getOrderSn ())
                .setMemberId (orderTo.getMemberId ())
                .setCreateTime (new Date ())
                .setStatus (OrderStatusEnum.CREATE_NEW.getCode ())
                .setPayAmount (multiply);
        //缺少运费信息

        //保存订单
        this.save (entity);

        //TODO 保存订单项
        OrderItemEntity itemEntity = new OrderItemEntity ()
                .setOrderSn (orderTo.getOrderSn ())
                .setRealAmount (multiply)
                //TODO 获取当前SKU的详细信息进行设置productFeignService.spuInfoBySkuId ()
                .setSkuQuantity (orderTo.getNum ());

        //保存SPU
        R spuInfo = productFeignService.spuInfoBySkuId(orderTo.getSkuId());
        SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>() {
        });
        itemEntity.setSpuId(spuInfoData.getId())
        .setSpuName(spuInfoData.getSpuName())
        .setSpuBrand(spuInfoData.getSpuName ())
        .setCategoryId(spuInfoData.getCatalogId());

        orderItemService.save (itemEntity);

    }


    /**
     * 保存订单数据
     *
     * @param order
     */
    private void saveOrder(OrderCreateTo order) {
        //1、订单
        OrderEntity order1 = order.getOrder ();
        order1.setModifyTime (new Date ());
        order1.setCreateTime (new Date ());
        this.save (order1);

        //订单项、一个订单要买好多东西
        List<OrderItemEntity> orderItems = order.getOrderItems ();
        orderItemService.saveBatch (orderItems);

    }

    /**
     * 创建订单
     * 创建订单号、
     * 获取到所有订单项
     * 验价
     *
     * @return
     */
    public OrderCreateTo orderCreateTo() {

        //订单创建的对象
        OrderCreateTo createTo = new OrderCreateTo ();
        //1、生成订单号
        String orderSn = IdWorker.getTimeId ();
        //创建订单号
        OrderEntity orderEntity = buildOrder (orderSn);

        //2、获取到所有订单项
        List<OrderItemEntity> itemEntities = buildOrderItems (orderSn);

        //3、验价（专门计算价格的）
        computePrice (orderEntity, itemEntities);

        createTo.setOrder (orderEntity);
        createTo.setOrderItems (itemEntities);
        return createTo;
    }

    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> itemEntities) {
        BigDecimal total = new BigDecimal ("0.0");
        BigDecimal coupon = new BigDecimal ("0.0");
        BigDecimal integration = new BigDecimal ("0.0");
        BigDecimal promotion = new BigDecimal ("0.0");

        BigDecimal gift = new BigDecimal ("0.0"); //积分
        BigDecimal growth = new BigDecimal ("0.0");//成长

        for (OrderItemEntity emEntity : itemEntities) {
            //订单的总额，叠加每一个订单项的总额信息
            coupon = coupon.add (emEntity.getCouponAmount ()); //优惠券优惠分解金额
            integration = integration.add (emEntity.getIntegrationAmount ());//积分优惠分解金额
            promotion = promotion.add (emEntity.getPromotionAmount ()); //商品促销分解金额

            total = total.add (emEntity.getRealAmount ());

            //能获得多少积分、就能获得多少成长值---订单的总积分和成长值又是一个叠加状态
            gift = gift.add (new BigDecimal (emEntity.getGiftIntegration ().toString ()));//积分信息
            growth = growth.add (new BigDecimal (emEntity.getGiftGrowth ().toString ()));//成长值

        }
        //1、订单价格相关
        orderEntity.setTotalAmount (total);
        //应付总额 --订单的总额+运费
        orderEntity.setPayAmount (total.add (orderEntity.getFreightAmount ()));
        orderEntity.setPromotionAmount (promotion);
        orderEntity.setIntegrationAmount (integration);
        orderEntity.setCouponAmount (coupon);

        //设置积分信息
        orderEntity.setIntegration (gift.intValue ());
        orderEntity.setGrowth (growth.intValue ());
        orderEntity.setDeleteStatus (0);//0未删除

    }

    //构建订单
    private OrderEntity buildOrder(String orderId) {
        MemberResVo memberResVo = LoginUserInterceptor.loinUser.get ();
        //创建订单号
        OrderEntity orderEntity = new OrderEntity ()
                .setOrderSn (orderId) //订单号
                .setMemberId (memberResVo.getId ()); //用户id

        OrderSubmitVo orderSubmitVo = confirmVo.get ();
        //获取收货人信息
        R fare = wmsFeignService.getFare (orderSubmitVo.getAddrId ());
        FareVo fareResp = fare.getDta (new TypeReference<FareVo> () {
        });

        //设置运费信息
        orderEntity.setFreightAmount (fareResp.getFare ())
                .setReceiverCity (fareResp.getAddress ().getCity ())
                .setReceiverDetailAddress (fareResp.getAddress ().getDetailAddress ())
                .setReceiverName (fareResp.getAddress ().getName ())
                .setReceiverPhone (fareResp.getAddress ().getPhone ())
                .setReceiverPostCode (fareResp.getAddress ().getPostCode ())
                .setReceiverProvince (fareResp.getAddress ().getProvince ())
                .setReceiverRegion (fareResp.getAddress ().getRegion ());


        //设置订单的相关状态信息
        orderEntity.setStatus (OrderStatusEnum.CREATE_NEW.getCode ());
        orderEntity.setAutoConfirmDay (7);

        return orderEntity;
    }


    //构建订单项
    private List<OrderItemEntity> buildOrderItems(String orderId) {
        //远程调用获取购物项
        List<OrderItemVo> currentUserCarItems = carFeignService.getCurrentUserCarItems ();
        if (currentUserCarItems != null && currentUserCarItems.size () > 0) {
            List<OrderItemEntity> collect = currentUserCarItems.stream ().map (carItem -> {
                //映射成订单信息
                OrderItemEntity itemEntity = buildOrderItem (carItem);
                itemEntity.setOrderSn (orderId);
                return itemEntity;
            }).collect (Collectors.toList ());
            return collect;
        }
        return null;
    }

    /**
     * 构建某一个订单项内容
     *
     * @param cartItem
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {

        OrderItemEntity itemEntity = new OrderItemEntity ();
        //1、订单信息：订单号

        //2、商品的SPU信息
        Long skuId = cartItem.getSkuId ();
        R r = productFeignService.spuInfoBySkuId (skuId);
        SpuInfoVo dta = r.getDta (new TypeReference<SpuInfoVo> () {
        });
        itemEntity.setSpuId (dta.getId ());
        itemEntity.setSpuBrand (dta.getBrandId ().toString ());
        itemEntity.setSpuName (dta.getSpuName ());
        itemEntity.setCategoryId (dta.getCatalogId ());

        //3、商品的SKU
        itemEntity.setSkuId (cartItem.getSkuId ())
                .setSkuName (cartItem.getTitle ())
                .setSkuPic (cartItem.getImage ())
                .setSkuPrice (cartItem.getPrice ());
        String s = StringUtils.collectionToDelimitedString (cartItem.getSkuAttr (), ";");
        itemEntity.setSkuAttrsVals (s)
                .setSkuQuantity (cartItem.getCount ());

        //4、优惠信息不做
        //5、积分信息
        itemEntity.setGiftGrowth (cartItem.getPrice ().multiply (new BigDecimal (cartItem.getCount ().toString ())).intValue ());
        itemEntity.setGiftIntegration (cartItem.getPrice ().multiply (new BigDecimal (cartItem.getCount ().toString ())).intValue ());

        //6、订单项的价格信息.
        itemEntity.setPromotionAmount (new BigDecimal ("0"));
        itemEntity.setCouponAmount (new BigDecimal ("0"));
        itemEntity.setIntegrationAmount (new BigDecimal ("0"));

        //当前订单项的实际金额。总额-各种优惠
        BigDecimal orign = itemEntity.getSkuPrice ().multiply (new BigDecimal (itemEntity.getSkuQuantity ().toString ()));

        BigDecimal subtract = orign.subtract (itemEntity.getCouponAmount ())
                .subtract (itemEntity.getPromotionAmount ())
                .subtract (itemEntity.getIntegrationAmount ());

        itemEntity.setRealAmount (subtract); //实际金额
        return itemEntity;
    }

}
